#include <QDebug>

#include "source/circuitswitching/circuitswitching.h"
#include "source/network/network.h"

int main(/*int argc, char *argv[]*/)
try {
  /// инициализация
  int controllableFlow = 1;     // контролируемый поток
  int limMessages      = 10000; // число сообщений для передачи

  double intensity        = 0.0001; // интенсивность сообщений потоков
  double messageLen       = 1.0;    // средняя длина сообщения
  double capacityChannels = 1.0;    // пропускная способность канлов сети
  double maxPackageLen    = 0.01;   // максимальная информационная длина пакета

  double switchingTimeCh = maxPackageLen / capacityChannels;         // время коммутации каналов
  double switchingTimeMP = (0.1 * maxPackageLen) / capacityChannels; // время коммутации сообщений или пакетов

  // длинна сообщения для потока

  // максимальная длина пакета

  // создание потоков
  Flow *flow1  = new Flow(intensity,   // интенсивность
                          messageLen); // средняя длина сообщения
  Flow *flow2  = new Flow(intensity, messageLen);
  Flow *flow3  = new Flow(intensity, messageLen);
  Flow *flow4  = new Flow(intensity, messageLen);
  Flow *flow5  = new Flow(intensity, messageLen);
  Flow *flow6  = new Flow(intensity, messageLen);
  Flow *flow7  = new Flow(intensity, messageLen);
  Flow *flow8  = new Flow(intensity, messageLen);
  Flow *flow9  = new Flow(intensity, messageLen);
  Flow *flow10 = new Flow(intensity, messageLen);
  Flow *flow11 = new Flow(intensity, messageLen);
  Flow *flow12 = new Flow(intensity, messageLen);
  Flow *flow13 = new Flow(intensity, messageLen);
  Flow *flow14 = new Flow(intensity, messageLen);

  // создание каналов связи
  Channel *channel1  = new Channel();
  Channel *channel2  = new Channel();
  Channel *channel3  = new Channel();
  Channel *channel4  = new Channel();
  Channel *channel5  = new Channel();
  Channel *channel6  = new Channel();
  Channel *channel7  = new Channel();
  Channel *channel8  = new Channel();
  Channel *channel9  = new Channel();
  Channel *channel10 = new Channel();
  Channel *channel11 = new Channel();
  /*
  // Возможная реализация создания узлов
  Hub *hub12 = new Hub("",   "1,4-14", // входные и выходные потоки
                       "11", "",       // входные и выходные каналы
                       NULL);          // предок
  Hub *hub10 = new Hub("",        "2,3", "8,9,10", "11", hub12);
  Hub *hub7  = new Hub("",        "",    "5,6,7",  "8",  hub10);
  Hub *hub9  = new Hub("14",      "",    "",       "9",  hub10);
  Hub *hub11 = new Hub("13",      "",    "",       "10", hub10);
  Hub *hub5  = new Hub("5,6,7,8", "",    "4",      "5",  hub7);
  Hub *hub6  = new Hub("11,12",   "",    "",       "6",  hub7);
  Hub *hub8  = new Hub("9,10",    "",    "",       "7",  hub7);
  Hub *hub3  = new Hub("1",       "",    "1,2,3",  "4",  hub5);
  Hub *hub1  = new Hub("3",       "",    "",       "1",  hub3);
  Hub *hub2  = new Hub("4",       "",    "",       "2",  hub3);
  Hub *hub4  = new Hub("2",       "",    "",       "3",  hub3);
  */

  // создание иерархии узлов
  Hub *hub12 = new Hub;
  Hub *hub10 = new Hub(hub12);
  Hub *hub9  = new Hub(hub10);
  Hub *hub11 = new Hub(hub10);
  Hub *hub7  = new Hub(hub10);
  Hub *hub6  = new Hub(hub7);
  Hub *hub8  = new Hub(hub7);
  Hub *hub5  = new Hub(hub7);
  Hub *hub3  = new Hub(hub5);
  Hub *hub2  = new Hub(hub3);
  Hub *hub4  = new Hub(hub3);
  Hub *hub1  = new Hub(hub3);

  // назначение имен узлам
  hub1->setObjectName("hub1");
  hub2->setObjectName("hub2");
  hub3->setObjectName("hub3");
  hub4->setObjectName("hub4");
  hub5->setObjectName("hub5");
  hub6->setObjectName("hub6");
  hub7->setObjectName("hub7");
  hub8->setObjectName("hub8");
  hub9->setObjectName("hub9");
  hub10->setObjectName("hub10");
  hub11->setObjectName("hub11");
  hub12->setObjectName("hub12");

  // создание списка потоков
  QList<Flow *> flows;
  flows.append(flow1);
  flows.append(flow2);
  flows.append(flow3);
  flows.append(flow4);
  flows.append(flow5);
  flows.append(flow6);
  flows.append(flow7);
  flows.append(flow8);
  flows.append(flow9);
  flows.append(flow10);
  flows.append(flow11);
  flows.append(flow12);
  flows.append(flow13);
  flows.append(flow14);

  // создание списка каналов связи
  QList<Channel *> channels;
  channels.append(channel1);
  channels.append(channel2);
  channels.append(channel3);
  channels.append(channel4);
  channels.append(channel5);
  channels.append(channel6);
  channels.append(channel7);
  channels.append(channel8);
  channels.append(channel9);
  channels.append(channel10);
  channels.append(channel11);

  // создание списка узлов
  QList<Hub *> hubs;
  hubs.append(hub1);
  hubs.append(hub2);
  hubs.append(hub3);
  hubs.append(hub4);
  hubs.append(hub5);
  hubs.append(hub6);
  hubs.append(hub7);
  hubs.append(hub8);
  hubs.append(hub9);
  hubs.append(hub10);
  hubs.append(hub11);
  hubs.append(hub12);

  // добавление входных потоков в узлы
  hub1->addInFlow(3);

  hub2->addInFlow(4);

  hub3->addInFlow(1);

  hub4->addInFlow(2);

  hub5->addInFlow(5);
  hub5->addInFlow(6);
  hub5->addInFlow(7);
  hub5->addInFlow(8);

  hub6->addInFlow(11);
  hub6->addInFlow(12);

  hub8->addInFlow(9);
  hub8->addInFlow(10);

  hub9->addInFlow(14);

  hub11->addInFlow(13);

  // добавление выходных потоков в узлы
  hub10->addOutFlow(2);
  hub10->addOutFlow(3);

  hub12->addOutFlow(1);
  for (int i = 4; i < countStreams; ++i) {
    hub12->addOutFlow(i);
  }

  // добавление каналов
  hub1->setOutChannel(channel1);

  hub2->setOutChannel(channel2);

  hub3->addInChannel(channel1);
  hub3->addInChannel(channel2);
  hub3->addInChannel(channel3);
  hub3->setOutChannel(channel4);

  hub4->setOutChannel(channel3);

  hub5->addInChannel(channel4);
  hub5->setOutChannel(channel5);

  hub6->setOutChannel(channel6);

  hub7->addInChannel(channel5);
  hub7->addInChannel(channel6);
  hub7->addInChannel(channel7);
  hub7->setOutChannel(channel8);

  hub8->setOutChannel(channel7);

  hub9->setOutChannel(channel9);

  hub10->addInChannel(channel8);
  hub10->addInChannel(channel9);
  hub10->addInChannel(channel10);
  hub10->setOutChannel(channel11);

  hub11->setOutChannel(channel10);

  hub12->addInChannel(channel11);

  // структура сети
  Network network;
  network.flows            = flows;            // потоки
  network.hubs             = hubs;             // узлы
  network.channels         = channels;         // каналы
  network.capacityChannels = capacityChannels; // пропускная способность канлов сети

  // коммутация каналов
  CircuitSwitching cs(network,          // структура сети
                      switchingTimeCh,  // время коммутации каналов
                      controllableFlow, // контралируемый поток
                      limMessages);     // число сообщений для передачи

  return 0;
}
catch (exception &e) {
  qDebug() << "error: " << e.what() << endl;
  return 1;
}
catch (...) {
  qDebug() << "Ой, неизвестное исключение.\n";
  return 2;
}
